#include "HL2Interface.h"

HL2Interfaces g_pInterfaces;

/////////////////////////////////////////////////////
// Hooks

CUserCmd* __stdcall hkGetUserCmd(int seq)
{
	DWORD GetUserCmd = *(DWORD*)((DWORD)g_pInterfaces.g_pInput + 0xB4) + (seq  % 90 << 6);
	CUserCmd* pCmd = (CUserCmd*)GetUserCmd;
	// NonShake NoSpread, Seed Triggers, etc. (command_number / seed, can be abused here)
	return pCmd;
}

void __fastcall hkCreateMove(void* thisptr, int edx, int sequence_number, float input_sample_frametime, bool active) 
{
	typedef void (__thiscall *CreateMove_t) (void*, int sequence_number, float input_sample_frametime, bool active);
	g_pInterfaces.g_pClientHooks->GetMethod<CreateMove_t>(CLIENT_CREATEMOVE)(thisptr, sequence_number, input_sample_frametime, active);
	if(!g_pInterfaces.g_pInput)
		return;

	CVerifiedUserCmd* pSafeCommand = *reinterpret_cast<CVerifiedUserCmd**>((size_t)g_pInterfaces.g_pInput + 0xB8) + (sequence_number % 90);
	CUserCmd* pCmd = g_pInterfaces.g_pInput->GetUserCmd(sequence_number); 

	if(!pCmd)
		return;

	// Modify The UserCmd here (Aimbots, Triggerbots, NoSpread, NoRecoil, etc.)
	g_pAimbot.AimAtTarget(pCmd);

	g_pNoSpread.ApplyNoRecoil(pCmd);

	g_pNoSpread.GetSpreadFix(pCmd->random_seed, pCmd->viewangles, g_pNoSpread.SpreadFix);
	pCmd->viewangles.Add(g_pNoSpread.SpreadFix);

	g_pNoSpread.SpreadFix.Clear();

	pSafeCommand->m_cmd = *pCmd;
	pSafeCommand->m_crc = pSafeCommand->m_cmd.GetChecksum();
}

void __fastcall hkPaintTraverse(void* thisptr, int edx, unsigned int vguiPanel, bool forceRepaint, bool allowForce)
{
	typedef const char* (__thiscall* GetName_t)(void*, unsigned int);
	const char* name = g_pInterfaces.g_pPanelHooks->GetMethod<GetName_t>(PANEL_GETNAME)(thisptr, vguiPanel);

	typedef void (__thiscall *PaintTraverse_t)(void* thisptr, unsigned int vguiPanel, bool forceRepaint, bool allowForce);
	g_pInterfaces.g_pPanelHooks->GetMethod<PaintTraverse_t>(PANEL_PAINTTRAVERSE)(thisptr, vguiPanel, forceRepaint, allowForce);

	if(name[0] == 'M' && name[3] == 'S' && name[9] == 'T' && name[12] == 'P') // [M]at[S]ystem[T]op[P]anel
	{
		// Draw Here
		g_pFont->PrintString(15, 15, 255, 255, 255, 255, FA_Left|FA_CenterH, "OSH-Mogelwerkzeug Basehook: Kotet By SilverDeath & rawc0de");
		if(!g_pInterfaces.g_pEngine->IsInGame())
			return;
		//////////////////////////////////////////////////////////////////////////
		int MaxEntities = g_pInterfaces.g_pEntList->GetHighestEntityIndex();
		int LocalPlayerIndex = g_pInterfaces.g_pEngine->GetLocalPlayer();
		Entity* LocalEntity = g_pInterfaces.g_pEntList->GetClientEntity(LocalPlayerIndex);

		bool DrawnEntity[32] = { false };

		SD_Tools::Vector2 ScreenSize;
		int tempa;
		int tempb;
		g_pInterfaces.g_pEngine->GetScreenSize(tempa, tempb);
		ScreenSize.x = (float) tempa;
		ScreenSize.y = (float) tempb;
		player_info_t pinfo;

		//////////////////////////////////////////////////////////////////////////

		printf("\nLocalEntity: 0x%08X\n\n", LocalEntity);

		//////////////////////////////////////////////////////////////////////////

		for (int i = 0; i < MaxEntities; i++)
		{
			if(i == LocalPlayerIndex)
				continue;
			Entity* baseEnt = g_pInterfaces.g_pEntList->GetClientEntity(i);

			if(!baseEnt || *baseEnt->dormant())
				continue;

			if(*baseEnt->lifeState() != 0 || !g_pInterfaces.g_pEngine->GetPlayerInfo(i, &pinfo))
				continue;

			//////////////////////////////////////////////////////////////////////////

			printf("Entity(%d): 0x%08X\n", i, baseEnt);

			//////////////////////////////////////////////////////////////////////////

			SD_Tools::Vector bot = *baseEnt->vecOrigin();
			SD_Tools::Vector top = SD_Tools::MathHelper::AddVector(bot, SD_Tools::Vector(0.f, 0.f, 70.f));

			SD_Tools::Vector2 sbot, stop;
			
			if(!WorldToScreen(g_pInterfaces.g_pEngine->WorldToScreenMatrix(), ScreenSize, bot, &sbot))
				continue;
			
			if(!WorldToScreen(g_pInterfaces.g_pEngine->WorldToScreenMatrix(), ScreenSize, top, &stop))
				continue;

			float h = sbot.y - stop.y;
			float w = h / 4.f;

			GRender.CornerBox(stop.x - w, stop.y, 10, w * 2, h, 255, 0, 0, 255);

			//g_pFont->PrintString(bot.x, bot.y, 255, 255, 0, 255, FA_Left, pinfo.name);
		}

		// Ka wo du das hintun willst, muss man nur 1x machen
		//DWORD TempAdd =  0xDEADBEEF; // Memory::FindPattern(0xDEADBEEF /*ClientBase*/, 0xDEADBEEF /*ClientSize*/, (BYTE*) RadarStructFindPatternA, RadarStructFindPatternB);
		//TempAdd += RadarStructOffset;
		//RadarClass* MyRadarPlayers = (RadarClass*) *(DWORD*) (**(DWORD**)TempAdd + 0xC);

		//for (int i = 0; i < 32; i++)
		//{
		//	if (DrawnEntity[i])
		//	{
		//		continue;
		//	}
		//	if (MyRadarPlayers->Players[i].Hp <= 0)
		//	{
		//		continue;
		//	}
		//	SD_Tools::Vector Head;
		//	SD_Tools::Vector Foot;

		//	Foot = MyRadarPlayers->Players[i].Position;
		//	Head = Foot;

		//	Head.z += 74.0f;
		//	Foot.z -= 10.0f;

		//	SD_Tools::Vector2 ScreenHead;
		//	SD_Tools::Vector2 ScreenFoot;

		//	if (!WorldToScreen(g_pInterfaces.g_pEngine->WorldToScreenMatrix(), ScreenSize, Head, &ScreenHead))
		//	{
		//		continue;
		//	}
		//	if (!WorldToScreen(g_pInterfaces.g_pEngine->WorldToScreenMatrix(), ScreenSize, Foot, &ScreenFoot))
		//	{
		//		continue;
		//	}

		//	float Size = SD_Tools::MathHelper::GetDiff(ScreenHead.y, ScreenFoot.y);
		//	float Width = Size / 2.0f;

		//	if (Size > 0.001f)
		//	{
		//		if (MyRadarPlayers->Players[LocalPlayerIndex-1].Team == MyRadarPlayers->Players[i].Team)
		//		{
		//			// Das darfst du machen :P
		//			// Blabla.DrawRect(ScreenFoot.x - Width/2, ScreenHead.y, Size, Width, 0xCOLOR);
		//		}
		//		else
		//		{
		//			// Todo
		//		}
		//	}
		//}

		//////////////////////////////////////////////////////////////////////////

	}
}

/////////////////////////////////////////////////////
// Base Funcs

void HL2Interfaces::Start()
{
	if(WaitForGame())
	{
		LoadInterfaces();
		g_pNetvars.PullOffsets();
	}
}

bool HL2Interfaces::WaitForGame()
{
	HANDLE hClient = NULL, hEngine = NULL, hVGUI = NULL, hVGUI2 = NULL;
	while(!hClient || !hEngine || !hVGUI || !hVGUI2)
	{
		hClient = GetModuleHandle(L"client.dll");
		hEngine = GetModuleHandle(L"engine.dll");
		hVGUI   = GetModuleHandle(L"vguimatsurface.dll");
		hVGUI2	= GetModuleHandle(L"vgui2.dll");
	}
	return true;
}

void HL2Interfaces::LoadInterfaces()
{
	//////////////////////////////////////////////////////////////////////////

	AllocConsole();
	freopen("CONOUT$", "w", stdout);
	freopen("CONOUT$", "w", stderr);
	freopen("CONIN$", "r", stdin);
	SetConsoleTitle(L"Rawc0de der nub");
	system("color 05");

	//////////////////////////////////////////////////////////////////////////


	CreateInterfaceFn fnClient = NULL;
	CreateInterfaceFn fnEngine = NULL;
	CreateInterfaceFn fnVGUI   = NULL;
	CreateInterfaceFn fnVGUI2  = NULL;

	fnClient = (CreateInterfaceFn)(GetProcAddress(LoadLibrary(L"client.dll"), "CreateInterface"));
	fnEngine = (CreateInterfaceFn)(GetProcAddress(LoadLibrary(L"engine.dll"), "CreateInterface"));
	fnVGUI	 = (CreateInterfaceFn)(GetProcAddress(LoadLibrary(L"vguimatsurface.dll"), "CreateInterface"));
	fnVGUI2	 = (CreateInterfaceFn)(GetProcAddress(LoadLibrary(L"vgui2.dll"), "CreateInterface"));

	g_pClient		= (IBaseClientDLL*)fnClient("VClient016", NULL);
	g_pEntList		= (IClientEntityList*)fnClient("VClientEntityList003", NULL);
	g_pEngine		= (IVEngineClient*)fnEngine("VEngineClient014", NULL);
	g_pEngineTrace  = (IEngineTrace*)fnEngine("EngineTraceClient003", NULL);
	void* vPanel	= fnVGUI2("VGUI_Panel009", NULL);
	void* vReplay	= fnEngine("EngineClientReplay001", NULL);
	g_pInput		= (CInput*)**(DWORD**)(g_pMemory.FindPattern((DWORD)GetModuleHandle(L"client.dll"), 0x899FFC, (BYTE*)InputFindPatternA, InputFindPatternB) + 2);

	g_pSurface.Init((PDWORD_PTR*)fnVGUI("VGUI_Surface030", NULL));
	g_pFont = g_pFont->BuildFont("Helvetica", 14, 350, FF_OUTLINE|FF_DROPSHADOW);

	if(g_pInput)
	{
		static hook_t InputHook((void*)g_pInput);
		g_pInputHooks = &InputHook;
		InputHook.HookMethod(&hkGetUserCmd, INPUT_GETUSERCMD);
	}

	if(g_pClient)
	{
		static hook_t ClientHook((void*)g_pClient);
		g_pClientHooks = &ClientHook;
		ClientHook.HookMethod(&hkCreateMove, CLIENT_CREATEMOVE);
	}

	if(vPanel)
	{
		static hook_t PanelHook(vPanel);
		g_pPanelHooks = &PanelHook;
		PanelHook.HookMethod(&hkPaintTraverse, PANEL_PAINTTRAVERSE);
	}

	if(vReplay)
	{
		hook_t ReplayHook(vReplay);
		typedef CGlobalVarsBase* (__thiscall* GetGlobalVars_t)(void*);
		g_pGlobals = ReplayHook.GetMethod<GetGlobalVars_t>(REPLAY_GETGLOBALVARS)(vReplay);
	}
}